package 
{
	import flash.display.Loader;
	import flash.display.Sprite;
	import flash.events.Event;
	import flash.events.KeyboardEvent;
	import flash.geom.Rectangle;
	import flash.net.URLLoader;
	import flash.net.URLRequest;
	import com.shortybmc.data.parser.CSV;
	import flash.printing.PrintJob;
	import flash.ui.Keyboard;
	
	/**
	 * ...
	 * @author Paul Forest
	 */
	[SWF(width = "612", height = "792", backgroundColor = "#ffffff", frameRate = "30")]
	public class Main extends Sprite 
	{
		private var csv:CSV = null;
		private const removeQuotes:RegExp = /^\"(.*)\"$/;
		
		public var people:Vector.<Person> = null;
		public var matches:Vector.<Match> = null;
		public var stations:Vector.<Station> = null;
		
		public function Main():void 
		{
			if (stage) init();
			else addEventListener(Event.ADDED_TO_STAGE, init);
		}
		
		private function init(e:Event = null):void 
		{
			removeEventListener(Event.ADDED_TO_STAGE, init);
			// entry point
			
			csv = new CSV();
			csv.addEventListener(Event.COMPLETE, onLoadComplete);
			csv.fieldSeperator = ",";
			csv.recordsetDelimiter = "\n";
			csv.fieldEnclosureToken = "\"";
			csv.load(new URLRequest("April2012Matches.csv"));
			
			stations = new Vector.<Station>();
			stations.push(new Station("123", "611"));
			stations.push(new Station("124", "611"));
			stations.push(new Station("125", "612"));
			stations.push(new Station("126", "612"));
			stations.push(new Station("127", "612"));
		}
		
		private function onLoadComplete(e:Event):void 
		{
			trace("onLoadComplete()");
			csv.removeEventListener(Event.COMPLETE, onLoadComplete); //necessary?
			
			var numRows:int = csv.data.length;
			
			people = new Vector.<Person>();
			
			for (var i:int = 0; i < numRows; i++) {
				var firstName:String = csv.data[i][1];
				if (firstName) {
					firstName = firstName.replace(removeQuotes, "$1");
				}
				
				var lastName:String = csv.data[i][4];
				if (lastName) {
					lastName = lastName.replace(removeQuotes, "$1");
				}
				
				var email:String = csv.data[i][5];
				if (email) {
					email = email.replace(removeQuotes, "$1");
				}
				
				var url:String = csv.data[i][6];
				if (url) {
					url = url.replace(removeQuotes, "$1");
				}
				
				var s:String = String(csv.data[i][2]).replace(removeQuotes, "$1");
				var hasSkillsUnprocessed:Array = s.split(",");
				hasSkillsUnprocessed = shortenSkillNames(hasSkillsUnprocessed);
				
				s = String(csv.data[i][3]).replace(removeQuotes, "$1");
				var wantsSkillsUnprocessed:Array = String(s).split(",");
				wantsSkillsUnprocessed = shortenSkillNames(wantsSkillsUnprocessed);
				
				
				var person:Person = new Person(firstName, lastName, email, url,
					Vector.<String>(hasSkillsUnprocessed),
					Vector.<String>(wantsSkillsUnprocessed)
					);
					
				people.push(person);
				//trace(person);/**/
			}
			
			createMatches(7, people);
		}
		
		
		private function shortenSkillNames(skillsArray:Array):Array 
		{
			const SoundEffectsRegex:RegExp = /Sound Effects \/ Audio/;
			const SoundEffectsReplace:String = "SFX";
			const ProducerRegex:RegExp = /Producer \/ Project Manager/;
			const ProducerReplace:String = "Producer";
			const QARegex:RegExp = /Quality Assurance/;
			const QAReplace:String = "QA";
			const BusinessRegex:RegExp = /Other \(Business \/ Marketing \/ Publishing \/ Legal \/ Human Resources or anything else\)/;
			const BusinessReplace:String = "Business ";
			
			var len:int = skillsArray.length;
			for (var i:int = 0; i < len; i++) {
				var s:String = skillsArray[i];
				s = s.replace(SoundEffectsRegex, SoundEffectsReplace);
				s = s.replace(ProducerRegex, ProducerReplace);
				s = s.replace(QARegex, QAReplace);
				s = s.replace(BusinessRegex, BusinessReplace);
				
				skillsArray[i] = s;
			}
			return skillsArray;
		}
		
		/**
		 * General algortithm:
	     * for all Rounds R:
		 * 		for all Person P1 in people:
		 * 			set match found to false
		 * 			for all Person P2 in people:
		 * 				if P1 != P2 and !doesMatchExist(P1,P2) and !P2.isBusy(R) and getMatchScore(P1,P2)>0:
		 * 					createMatch( P1, P2, R)
		 * 					save in results
		 * 			if there are any results:
		 *          	sort results by score
		 * 				use the top scoring result as a new match; discard the rest
		 *          else:
	     *              warn that we can't find a match
		 * 				???
		 * 
		 * @param	people
		 */
		private function createMatches(maxRounds:int, peeps:Vector.<Person>):void 
		{
			matches = new Vector.<Match>();
			
			for (var round:int = 0; round < maxRounds; round++) {
				Util.shuffleVector(peeps).forEach( function (firstPerson:Person, firstIndex:int, vector1:Vector.<Person>):void {
					
					var results:Vector.<Match> = new Vector.<Match>();
					
					Util.shuffleVector(peeps).forEach( function (secondPerson:Person, secondIndex:int, vector2:Vector.<Person>):void {
						
						if (firstPerson == secondPerson) {
							return;
						}
						
						if (firstPerson.doesMatchExistWith(secondPerson)) {
							return;
						}
						
						if (firstPerson.isBusyInRound(round) || secondPerson.isBusyInRound(round)) {
							return;
						}
						
						var score:int = firstPerson.getMatchScoreTo(secondPerson);
						if (score > 0) {
							var match:Match = new Match(firstPerson, secondPerson, null, round, score);
							results.push(match);
						}
						
					}, this);
					
					if (results.length > 0) {
						results = results.sort(Match.sortOnScore);
						var bestMatch:Match = results[0];
						bestMatch.station = getBestStation();
						matches.push(bestMatch);
						
						bestMatch.person1.matches.push(bestMatch);
						bestMatch.person2.matches.push(bestMatch);
						
						//trace("winner: " + bestMatch);
					} else {
						trace("Can't find a match for: " + firstPerson);
					}
				}, this);
			}
			
			initUI();
		}
		
		
		
		private function getBestStation():Station 
		{
			return stations[ Math.floor(Math.random() * stations.length) ];
		}
		
		private function initUI():void {
			personIndex = 0;
			showPersonByIndex(personIndex);
			
			stage.addEventListener(KeyboardEvent.KEY_DOWN, onKeyDownEvent);
			
			//trace("people.length=" + people.length);
		}
		
		private var personIndex:int = 0;
		private var shownMatchCard:MatchCardUI = null;
		
		private function showPersonByIndex(index:int):void {
			//trace("showPersonByIndex(): " + index);
			
			if (shownMatchCard) { 
				removeChild(shownMatchCard);
				shownMatchCard = null;
			}
			var matchCard:MatchCardUI = new MatchCardUI(people[index]);
			addChild(matchCard);
			shownMatchCard = matchCard;
		}
		
		private function onKeyDownEvent(e:KeyboardEvent):void 
		{
			switch (e.keyCode) {
				
				case Keyboard.LEFT:
					personIndex --;
					if (personIndex < 0) {
						personIndex = people.length - 1;
					}
					showPersonByIndex(personIndex);
					break;
					
				case Keyboard.RIGHT:
					personIndex ++;
					if (personIndex > people.length - 1) {
						personIndex = 0;
					}
					showPersonByIndex(personIndex);
					break;
					
				case 80:
					printPage();
					break;
					
				case 81:
					printAllPages();
					break;
					
				default:
					break;
			}
		}
		
		private var isPrinting:Boolean = false;
		private var myPrintJob:PrintJob = null;
		private var peopleLen:int = 0;
		private var printIndex:int = 0;
		
		private function printAllPages():void 
		{
			trace("printAllPages()");
			if (isPrinting) {
				trace("printAllPages(): can't print, there's already a print in progress");
				return;
			}
			
			isPrinting = true;
			myPrintJob = new PrintJob();

			var result:Boolean = myPrintJob.start();
			if (result)
			{
				trace("		printing ... ");
				
				printIndex = 0;
				peopleLen = people.length;
				
				var me:Main = this;
				var printOne:Function = function (e:Event):void {
					if (printIndex < peopleLen) {
						showPersonByIndex(printIndex);
						myPrintJob.addPage(me, new Rectangle(0, 0, 576, 756));
						printIndex++;
					} else {
						me.removeEventListener(Event.ENTER_FRAME, printOne);
						
						myPrintJob.send();
						myPrintJob = null;
						isPrinting = false;
					}
				}
				
				addEventListener(Event.ENTER_FRAME, printOne);
				
				/*for (var i:int = 0; i < peopleLen; i++) {
					showPersonByIndex(i);
					myPrintJob.addPage(this, new Rectangle(0, 0, 576, 756));
				}*/
				
			} else {
				myPrintJob = null;
				
				//User does not have printer or user canceled print action
				trace("NO PRINTER OR CANCELLED!");
			}			
		}
		
		
		
		private function printPage():void 
		{
			trace("print page");
			var myPrintJob:PrintJob = new PrintJob();
			var result:Boolean = myPrintJob.start();

			if (result)
			{
				myPrintJob.addPage(this, new Rectangle(0, 0, 576, 756));

				myPrintJob.send();

				myPrintJob = null;
				trace("		printing ... ");
			} else {
				//User does not have printer or user canceled print action
				trace("NO PRINTER OR CANCELLED!");
			}			
		}
	}
}